Skip to content

Replace hidapi with hidra#131

Open
carlossless wants to merge 6 commits into
masterfrom
hidra
Open

Replace hidapi with hidra#131
carlossless wants to merge 6 commits into
masterfrom
hidra

Conversation

@carlossless

Copy link
Copy Markdown
Owner

Swaps the hidapi dependency for hidra, a pure-Rust HID library. This removes the C/libusb build dependency (no pkg-config or system libusb needed).

Changes

  • Cargo.toml: hidapi -> hidra (git dependency, usb feature).
  • New src/hid.rs: selects the backend per platform, matching the old linux-static-libusb setup. Linux uses hidra's nusb-based usb backend; Windows and macOS use the native HID stack. Both expose the same method surface, so the rest of the tool is unchanged.
  • Mechanical updates in device_selector.rs, isp_device.rs, util.rs: device paths are &str instead of &CStr, BusType is compared directly, and is_expected_error matches hidra's typed HidError variants instead of backend-specific message strings.

Testing

Verified end-to-end against real hardware (a NuPhy Air60) on all three desktop platforms, performing the full ISP flash cycle:

  • Linux (nusb backend): list, read, and write all produce output byte-identical to the hidapi build; firmware read+write round-trips verified by MD5.
  • Windows (native hid.dll backend): list, read, write all working.
  • macOS (IOHIDManager backend): list, read, write all working.

Unit tests pass. The tests/list_test.rs integration tests fail in my environment, but they fail identically on master with hidapi: they snapshot a stock-firmware keyboard, and my test unit runs custom firmware. They are not affected by this change.

- actions/checkout v4 -> v6
- actions/cache v4 -> v5
- actions/upload-artifact v4 -> v7
- actions/download-artifact v4 -> v8
- cachix/cachix-action v14 -> v17
- softprops/action-gh-release v2 -> v3

cachix/install-nix-action is already on the latest major (v31).
hidra now exposes one HidApi/HidDevice whose I/O methods return futures
(the nusb-model redesign); there is no separate hidra::usb. Adapt:

- hid.rs: re-export the single hidra::{HidApi, HidDevice} plus MaybeFuture;
  the `nusb` feature still selects hidra's nusb backend (now on the unified
  type), so the per-OS backend cfg aliasing is gone.
- device_selector.rs / isp_device.rs: drive the now-async open_path,
  get_report_descriptor, send_feature_report and get_feature_report calls
  with MaybeFuture::wait (the tool stays synchronous).
- Gate the macOS set_open_exclusive call on `not(feature = "nusb")` to match
  where hidra exposes it.
- Bump the hidra git pin to the redesigned commit.

Also drops a redundant comment on is_expected_error.
Extract the ISP bootloader protocol, device/platform specs, payload
utilities, and ihex helpers into a new sinowealth-isp library crate, and
keep the CLI in a sinowealth-kb-tool bin crate. Both live under crates/
in a virtual workspace.

The protocol is now expressed as async methods over hidra::HidDevice, so
the exact same code drives the native CLI (via MaybeFuture::wait) and a
future web flasher (via .await on wasm32 with the WebHID backend). To stay
UI- and runtime-free, the library:

- reports progress through a caller-supplied Progress callback instead of
  printing or driving indicatif directly (the CLI maps it onto a progress
  bar in progress.rs)
- waits for the device to settle through a cross-target async sleep (a
  thread-backed timer on native, setTimeout on the web) instead of
  thread::sleep
- takes an optional separate transfer handle (ISPDevice::new(.., None) on
  Linux/macOS/WebHID; Some(handle) for the Windows two-collection split),
  moving that platform branching to the CLI device selector

is_expected_error now cfg-gates the native-only HidError::Io variant so it
compiles for the web backend.

CI gains a wasm build check for sinowealth-isp; the nix build uses
singleStep so naersk handles the workspace layout.
sinowealth-isp now exposes only the individual ISP protocol operations
(enable_firmware, init_read/read_page, init_write/write_page, erase,
reboot) as async methods over hidra::HidDevice. The full read_cycle /
write_cycle orchestration, the page loops, progress reporting, and the
post-erase/reboot settle delays now live in the CLI (new flasher.rs).

This keeps the library free of orchestration, timing, and UI concerns:
- erase/reboot no longer sleep; callers insert the delay (the CLI uses
  thread::sleep, a web app uses setTimeout)
- the cross-target async sleep module is gone, so the library no longer
  needs js-sys/wasm-bindgen/web-sys/wasm-bindgen-futures (or log)
- the Progress callback is gone; the CLI drives indicatif directly in its
  own page loop

reboot now returns a Result instead of swallowing errors, so the caller
decides how to treat the expected disconnect (the CLI checks
is_expected_error on the unwrapped HidError).
The page loops (init_read + read_page x N, init_write + write_page x N)
are mechanical protocol with no timing, so they belong in the library as
ISPDevice::read/write rather than being duplicated in every consumer.

They take a dep-free '&dyn Fn(done, total)' progress callback, so the loop
stays in the lib without dragging back any runtime/UI dependency. The CLI
flasher (and the web app) now just create their progress bar, pass a
callback, and keep owning the surrounding cycle: sequencing, the
post-erase/reboot settle delays, and verification.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant